#pragma once
#include "CommType.h"
#include "Array.h"

namespace COMM
{
	class COMM_API IBind
	{
	protected:
		String m_classname;
	public:
		enum{MAX_ARG_COUNT=8};
		const char* ClassName() const{ return m_classname; }
		virtual ~IBind(){}
		virtual CommType Call(void) const = 0;
		virtual CommType Call(CommType p1) const = 0;
		virtual CommType Call(CommType p1,CommType p2) const = 0;
		virtual CommType Call(CommType p1,CommType p2,CommType p3) const = 0;
		virtual CommType Call(CommType p1,CommType p2,CommType p3,CommType p4) const = 0;
		virtual CommType Call(CommType p1,CommType p2,CommType p3,CommType p4,CommType p5) const = 0;
		virtual CommType Call(CommType p1,CommType p2,CommType p3,CommType p4,CommType p5,CommType p6) const = 0;
		virtual CommType Call(CommType p1,CommType p2,CommType p3,CommType p4,CommType p5,CommType p6,CommType p7) const = 0;
		virtual CommType Call(CommType p1,CommType p2,CommType p3,CommType p4,CommType p5,CommType p6,CommType p7,CommType p8) const = 0;
		
		CommType Call(const Arguments& args)
		{
			int argc = args.count();
			MYLIB_ASSERT(MAX_ARG_COUNT>=argc);
			if(1 == argc)
				return this->Call(args[0]);
			else if(2 == argc)
				return this->Call(args[0],args[1]);
			else if(3 == argc)
				return this->Call(args[0],args[1],args[2]);
			else if(4 == argc)
				return this->Call(args[0],args[1],args[2],args[3]);
			else if(5 == argc)
				return this->Call(args[0],args[1],args[2],args[3],args[4]);
			else if(6 == argc)
				return this->Call(args[0],args[1],args[2],args[3],args[4],args[5]);
			else if(7 == argc)
				return this->Call(args[0],args[1],args[2],args[3],args[4],args[5],args[6]);
			else if(8 == argc)
				return this->Call(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7]);
			return this->Call();
		}
	};

	template<class T, class R=void, 
	class P1=void*, class P2=void*, class P3=void*, class P4=void*, class P5=void*, class P6=void*, class P7=void*, class P8=void*>
	class Bind : public IBind
	{
	public:
		T& operator*() const{ return *m_inst;}
		T *get() const{ return m_inst;}
		void set(T* inst){ m_inst = inst;}

		virtual CommType Call(void) const
		{
			return operator()();
		}
		virtual CommType Call(CommType p1) const
		{
			return operator()(p1);
		}
		virtual CommType Call(CommType p1,CommType p2) const
		{
			return operator()(p1,p2);
		}
		virtual CommType Call(CommType p1,CommType p2,CommType p3) const
		{
			return operator()(p1,p2,p3);
		}
		virtual CommType Call(CommType p1,CommType p2,CommType p3,CommType p4) const
		{
			return operator()(p1,p2,p3,p4);
		}
		virtual CommType Call(CommType p1,CommType p2,CommType p3,CommType p4,CommType p5) const
		{
			return operator()(p1,p2,p3,p4,p5);
		}
		virtual CommType Call(CommType p1,CommType p2,CommType p3,CommType p4,CommType p5,CommType p6) const
		{
			return operator()(p1,p2,p3,p4,p5,p6);
		}
		virtual CommType Call(CommType p1,CommType p2,CommType p3,CommType p4,CommType p5,CommType p6,CommType p7) const
		{
			return operator()(p1,p2,p3,p4,p5,p6,p7);
		}
		virtual CommType Call(CommType p1,CommType p2,CommType p3,CommType p4,CommType p5,CommType p6,CommType p7,CommType p8) const
		{
			return operator()(p1,p2,p3,p4,p5,p6,p7,p8);
		}

		// 0 parameters
		//
		typedef R(T::*FuncPtr0)(void);
		Bind(T* inst,FuncPtr0 pfunc,const char* classname=NULL) :m_inst(inst){ Init();m_pfunc0=pfunc;m_classname=classname;}
		CommType operator ()(void) const { 
			if(NULL==m_pfunc0){ LOGWARN("invoking \"%s\" error: in-correct arguments count.",this->ClassName()); return CommType::Error;}; 
			return (m_inst->*m_pfunc0)(); 
		}

		// 1 parameters
		//
		typedef R(T::*FuncPtr1)(P1);
		Bind(T* inst,FuncPtr1 pfunc,const char* classname=NULL) :m_inst(inst){ Init();m_pfunc1=pfunc;m_classname=classname;}
		CommType operator ()(P1 p1) const { 
			if(NULL==m_pfunc1){ LOGWARN("invoking \"%s\" error: in-correct arguments count.",this->ClassName()); return CommType::Error;}; 
			return (m_inst->*m_pfunc1)(p1); 
		}

		// 2 parameters
		//
		typedef R(T::*FuncPtr2)(P1, P2);
		Bind(T* inst,FuncPtr2 pfunc,const char* classname=NULL) :m_inst(inst){ Init();m_pfunc2=pfunc;m_classname=classname;}
		CommType operator ()(P1 p1,P2 p2) const { 
			if(NULL==m_pfunc2){ LOGWARN("invoking \"%s\" error: in-correct arguments count.",this->ClassName()); return CommType::Error;}; 
			return (m_inst->*m_pfunc2)(p1,p2); 
		}

		// 3 parameters
		//
		typedef R(T::*FuncPtr3)(P1, P2, P3);
		Bind(T* inst,FuncPtr3 pfunc,const char* classname=NULL) :m_inst(inst){  Init();m_pfunc3=pfunc;m_classname=classname;}
		CommType operator ()(P1 p1,P2 p2,P3 p3) const { 
			if(NULL==m_pfunc3){ LOGWARN("invoking \"%s\" error: in-correct arguments count.",this->ClassName()); return CommType::Error;}; 
			return (m_inst->*m_pfunc3)(p1,p2,p3); 
		}

		// 4 parameters
		//
		typedef R(T::*FuncPtr4)(P1, P2, P3, P4);
		Bind(T* inst,FuncPtr4 pfunc,const char* classname=NULL) :m_inst(inst){ Init();m_pfunc4=pfunc;m_classname=classname;}
		CommType operator ()(P1 p1,P2 p2,P3 p3,P4 p4) const { 
			if(NULL==m_pfunc4){ LOGWARN("invoking \"%s\" error: in-correct arguments count.",this->ClassName()); return CommType::Error;}; 
			return (m_inst->*m_pfunc4)(p1,p2,p3,p4); 
		}

		// 5 parameters
		//
		typedef R(T::*FuncPtr5)(P1, P2, P3, P4, P5);
		Bind(T* inst,FuncPtr5 pfunc,const char* classname=NULL) :m_inst(inst){ Init();m_pfunc5=pfunc;m_classname=classname;}
		CommType operator ()(P1 p1,P2 p2,P3 p3,P4 p4,P5 p5) const { 
			if(NULL==m_pfunc5){ LOGWARN("invoking \"%s\" error: in-correct arguments count.",this->ClassName()); return CommType::Error;}; 
			return (m_inst->*m_pfunc5)(p1,p2,p3,p4,p5); 
		}

		// 6 parameters
		//
		typedef R(T::*FuncPtr6)(P1, P2, P3, P4, P5, P6);
		Bind(T* inst,FuncPtr6 pfunc,const char* classname=NULL) :m_inst(inst){ Init();m_pfunc6=pfunc;m_classname=classname;}
		CommType operator ()(P1 p1,P2 p2,P3 p3,P4 p4,P5 p5,P6 p6) const { 
			if(NULL==m_pfunc6){ LOGWARN("invoking \"%s\" error: in-correct arguments count.",this->ClassName()); return CommType::Error;}; 
			return (m_inst->*m_pfunc6)(p1,p2,p3,p4,p5,p6); 
		}

		// 7 parameters
		//
		typedef R(T::*FuncPtr7)(P1, P2, P3, P4, P5, P6, P7);
		Bind(T* inst,FuncPtr7 pfunc,const char* classname=NULL) :m_inst(inst){ Init();m_pfunc7=pfunc;m_classname=classname;}
		CommType operator ()(P1 p1,P2 p2,P3 p3,P4 p4,P5 p5,P6 p6,P7 p7) const { 
			if(NULL==m_pfunc7){ LOGWARN("invoking \"%s\" error: in-correct arguments count.",this->ClassName()); return CommType::Error;}; 
			return (m_inst->*m_pfunc7)(p1,p2,p3,p4,p5,p6,p7); 
		}

		// 8 parameters
		//
		typedef R(T::*FuncPtr8)(P1, P2, P3, P4, P5, P6, P7, P8);
		Bind(T* inst,FuncPtr8 pfunc,const char* classname=NULL) :m_inst(inst){ Init();m_pfunc8=pfunc;m_classname=classname;}
		CommType operator ()(P1 p1,P2 p2,P3 p3,P4 p4,P5 p5,P6 p6,P7 p7,P8 p8) const { 
			if(NULL==m_pfunc8){ LOGWARN("invoking \"%s\" error: in-correct arguments count.",this->ClassName()); return CommType::Error;}; 
			return (m_inst->*m_pfunc8)(p1,p2,p3,p4,p5,p6,p7,p8); 
		}

	private:
		FuncPtr0 m_pfunc0;
		FuncPtr1 m_pfunc1;
		FuncPtr2 m_pfunc2;
		FuncPtr3 m_pfunc3;
		FuncPtr4 m_pfunc4;
		FuncPtr5 m_pfunc5;
		FuncPtr6 m_pfunc6;
		FuncPtr7 m_pfunc7;
		FuncPtr8 m_pfunc8;
		void Init()
		{
			m_pfunc0 = NULL;
			m_pfunc1 = NULL;
			m_pfunc2 = NULL;
			m_pfunc3 = NULL;
			m_pfunc4 = NULL;
			m_pfunc5 = NULL;
			m_pfunc6 = NULL;
			m_pfunc7 = NULL;
			m_pfunc8 = NULL;
		}
		T* m_inst;
	};

	// R=void partial specialization.
	//
	template<class T, 
	class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8>
	class Bind<T,void,P1,P2,P3,P4,P5,P6,P7,P8> : public IBind
	{
	public:
		T& operator*() const{ return *m_inst;}
		T *get() const{ return m_inst;}
		void set(T* inst){ m_inst = inst;}

		virtual CommType Call(void) const
		{
			return operator()();
		}
		virtual CommType Call(CommType p1) const
		{
			return operator()(p1);
		}
		virtual CommType Call(CommType p1,CommType p2) const
		{
			return operator()(p1,p2);
		}
		virtual CommType Call(CommType p1,CommType p2,CommType p3) const
		{
			return operator()(p1,p2,p3);
		}
		virtual CommType Call(CommType p1,CommType p2,CommType p3,CommType p4) const
		{
			return operator()(p1,p2,p3,p4);
		}
		virtual CommType Call(CommType p1,CommType p2,CommType p3,CommType p4,CommType p5) const
		{
			return operator()(p1,p2,p3,p4,p5);
		}
		virtual CommType Call(CommType p1,CommType p2,CommType p3,CommType p4,CommType p5,CommType p6) const
		{
			return operator()(p1,p2,p3,p4,p5,p6);
		}
		virtual CommType Call(CommType p1,CommType p2,CommType p3,CommType p4,CommType p5,CommType p6,CommType p7) const
		{
			return operator()(p1,p2,p3,p4,p5,p6,p7);
		}
		virtual CommType Call(CommType p1,CommType p2,CommType p3,CommType p4,CommType p5,CommType p6,CommType p7,CommType p8) const
		{
			return operator()(p1,p2,p3,p4,p5,p6,p7,p8);
		}

		// 0 parameters
		//
		typedef void(T::*FuncPtr0)(void);
		Bind(T* inst,FuncPtr0 pfunc,const char* classname=NULL) :m_inst(inst){ Init();m_pfunc0=pfunc;m_classname=classname;}
		CommType operator ()(void) const { 
			if(NULL==m_pfunc0){ LOGWARN("invoking \"%s\" error: in-correct arguments count.",this->ClassName()); return CommType::Error;}; 
			(m_inst->*m_pfunc0)(); 
			return CommType::Void;
		}

		// 1 parameters
		//
		typedef void(T::*FuncPtr1)(P1);
		Bind(T* inst,FuncPtr1 pfunc,const char* classname=NULL) :m_inst(inst){ Init();m_pfunc1=pfunc;m_classname=classname;}
		CommType operator ()(P1 p1) const { 
			if(NULL==m_pfunc1){ LOGWARN("invoking \"%s\" error: in-correct arguments count.",this->ClassName()); return CommType::Error;}; 
			(m_inst->*m_pfunc1)(p1); 
			return CommType::Void;
		}

		// 2 parameters
		//
		typedef void(T::*FuncPtr2)(P1, P2);
		Bind(T* inst,FuncPtr2 pfunc,const char* classname=NULL) :m_inst(inst){ Init();m_pfunc2=pfunc;m_classname=classname;}
		CommType operator ()(P1 p1,P2 p2) const { 
			if(NULL==m_pfunc2){ LOGWARN("invoking \"%s\" error: in-correct arguments count.",this->ClassName()); return CommType::Error;}; 
			(m_inst->*m_pfunc2)(p1,p2); 
			return CommType::Void;
		}

		// 3 parameters
		//
		typedef void(T::*FuncPtr3)(P1, P2, P3);
		Bind(T* inst,FuncPtr3 pfunc,const char* classname=NULL) :m_inst(inst){  Init();m_pfunc3=pfunc;m_classname=classname;}
		CommType operator ()(P1 p1,P2 p2,P3 p3) const { 
			if(NULL==m_pfunc3){ LOGWARN("invoking \"%s\" error: in-correct arguments count.",this->ClassName()); return CommType::Error;}; 
			(m_inst->*m_pfunc3)(p1,p2,p3); 
			return CommType::Void;
		}

		// 4 parameters
		//
		typedef void(T::*FuncPtr4)(P1, P2, P3, P4);
		Bind(T* inst,FuncPtr4 pfunc,const char* classname=NULL) :m_inst(inst){ Init();m_pfunc4=pfunc;m_classname=classname;}
		CommType operator ()(P1 p1,P2 p2,P3 p3,P4 p4) const { 
			if(NULL==m_pfunc4){ LOGWARN("invoking \"%s\" error: in-correct arguments count.",this->ClassName()); return CommType::Error;}; 
			(m_inst->*m_pfunc4)(p1,p2,p3,p4); 
			return CommType::Void;
		}

		// 5 parameters
		//
		typedef void(T::*FuncPtr5)(P1, P2, P3, P4, P5);
		Bind(T* inst,FuncPtr5 pfunc,const char* classname=NULL) :m_inst(inst){ Init();m_pfunc5=pfunc;m_classname=classname;}
		CommType operator ()(P1 p1,P2 p2,P3 p3,P4 p4,P5 p5) const { 
			if(NULL==m_pfunc5){ LOGWARN("invoking \"%s\" error: in-correct arguments count.",this->ClassName()); return CommType::Error;}; 
			(m_inst->*m_pfunc5)(p1,p2,p3,p4,p5); 
			return CommType::Void;
		}

		// 6 parameters
		//
		typedef void(T::*FuncPtr6)(P1, P2, P3, P4, P5, P6);
		Bind(T* inst,FuncPtr6 pfunc,const char* classname=NULL) :m_inst(inst){ Init();m_pfunc6=pfunc;m_classname=classname;}
		CommType operator ()(P1 p1,P2 p2,P3 p3,P4 p4,P5 p5,P6 p6) const { 
			if(NULL==m_pfunc6){ LOGWARN("invoking \"%s\" error: in-correct arguments count.",this->ClassName()); return CommType::Error;}; 
			(m_inst->*m_pfunc6)(p1,p2,p3,p4,p5,p6); 
			return CommType::Void;
		}

		// 7 parameters
		//
		typedef void(T::*FuncPtr7)(P1, P2, P3, P4, P5, P6, P7);
		Bind(T* inst,FuncPtr7 pfunc,const char* classname=NULL) :m_inst(inst){ Init();m_pfunc7=pfunc;m_classname=classname;}
		CommType operator ()(P1 p1,P2 p2,P3 p3,P4 p4,P5 p5,P6 p6,P7 p7) const { 
			if(NULL==m_pfunc7){ LOGWARN("invoking \"%s\" error: in-correct arguments count.",this->ClassName()); return CommType::Error;}; 
			(m_inst->*m_pfunc7)(p1,p2,p3,p4,p5,p6,p7); 
			return CommType::Void;
		}

		// 8 parameters
		//
		typedef void(T::*FuncPtr8)(P1, P2, P3, P4, P5, P6, P7, P8);
		Bind(T* inst,FuncPtr8 pfunc,const char* classname=NULL) :m_inst(inst){ Init();m_pfunc8=pfunc;m_classname=classname;}
		CommType operator ()(P1 p1,P2 p2,P3 p3,P4 p4,P5 p5,P6 p6,P7 p7,P8 p8) const { 
			if(NULL==m_pfunc8){ LOGWARN("invoking \"%s\" error: in-correct arguments count.",this->ClassName()); return CommType::Error;}; 
			(m_inst->*m_pfunc8)(p1,p2,p3,p4,p5,p6,p7,p8); 
			return CommType::Void;
		}

	private:
		FuncPtr0 m_pfunc0;
		FuncPtr1 m_pfunc1;
		FuncPtr2 m_pfunc2;
		FuncPtr3 m_pfunc3;
		FuncPtr4 m_pfunc4;
		FuncPtr5 m_pfunc5;
		FuncPtr6 m_pfunc6;
		FuncPtr7 m_pfunc7;
		FuncPtr8 m_pfunc8;
		void Init()
		{
			m_pfunc0 = NULL;
			m_pfunc1 = NULL;
			m_pfunc2 = NULL;
			m_pfunc3 = NULL;
			m_pfunc4 = NULL;
			m_pfunc5 = NULL;
			m_pfunc6 = NULL;
			m_pfunc7 = NULL;
			m_pfunc8 = NULL;
		}
		T* m_inst;
	};
}





